package com.jyxd.web.service.assessment.basic;

import com.jyxd.web.dao.basic.BasicNursingSyncRecordDao;
import com.jyxd.web.dao.basic.PrimaryCareDao;
import com.jyxd.web.data.basic.BasicNursingSyncRecord;
import com.jyxd.web.data.basic.PrimaryCare;
import com.jyxd.web.data.dto.HttpResult;
import com.jyxd.web.mq.HisViewProduction;
import com.jyxd.web.service.hisview.dto.HisViewDataDto;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;

import static com.jyxd.web.config.ConstantConfig.HIS_VIEW_EVENT_DC_HLCZJL_BZBWHL_HLCZ;
import static com.jyxd.web.util.DateUtil.*;
import static com.jyxd.web.util.ExecuteUtil.errorIfEmpty;
import static com.jyxd.web.util.ExecuteUtil.errorIfFalse;
import static com.jyxd.web.util.UUIDUtil.getUUID;

@Service
public class BasicNursingSyncRecordService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private BasicNursingSyncRecordDao basicNursingSyncRecordDao;

    @Autowired
    private PrimaryCareDao primaryCareDao;

    @Autowired
    private HisViewProduction hisViewProduction;

    private final String NURSING_SYNC_INTERVAL_Q1 = "Q1";  // 同步间隔 （1小时1次）
    private final String NURSING_SYNC_INTERVAL_Q2 = "Q2";  // 同步间隔 （2小时1次）
    private final String NURSING_SYNC_INTERVAL_Q4 = "Q4";  // 同步间隔 （4小时1次）
    private final String NURSING_SYNC_INTERVAL_Q6 = "Q6";  // 同步间隔 （6小时1次）
    private final String NURSING_SYNC_INTERVAL_Q8 = "Q8";  // 同步间隔 （8小时1次）
    private final String NURSING_SYNC_INTERVAL_Q12 = "Q12"; // 同步间隔 （12小时1次）
    private final String NURSING_SYNC_INTERVAL_QD = "QD";  // 同步间隔 （1天1次）
    private final String NURSING_SYNC_INTERVAL_NO = "无";  // 同步间隔 （无）


    /**
     * 新增护理频次记录表
     *
     * @param map 患者id必传
     *            传参示例："hasCleanedMouth（口腔护理）" : "一日2次"，"patientId" : "123445"
     * @return
     */
    public HttpResult saveBasicNursingSyncRecord(Map<String, Object> map) {
        errorIfEmpty(map, "新增数据不能为空");
        errorIfEmpty(map.get("patientId"), "患者id不能为空");
        String patientId = (String) map.get("patientId");
        map.remove("patientId");
        for (Map.Entry<String, Object> data : map.entrySet()) {
            boolean estimateValue = estimateValue((String) data.getValue());
            errorIfFalse(estimateValue, "传入值数据有误，请传正确的value");
            BasicNursingSyncRecord basicNursingSyncRecord = findOldData(patientId, data.getKey());
            if (Objects.isNull(basicNursingSyncRecord)) {
                basicNursingSyncRecord = new BasicNursingSyncRecord();
                basicNursingSyncRecord.setId(getUUID());
                basicNursingSyncRecord.setPatientId(patientId);
                basicNursingSyncRecord.setCreateTime(new Date());
                basicNursingSyncRecord.setStatus(1);
                basicNursingSyncRecord.setCode(data.getKey());
                basicNursingSyncRecord.setContent((String) data.getValue());
                basicNursingSyncRecordDao.insert(basicNursingSyncRecord);
            } else {
                basicNursingSyncRecord.setSyncTime(null);
                basicNursingSyncRecord.setContent((String) data.getValue());
                basicNursingSyncRecordDao.update(basicNursingSyncRecord);
            }
        }
        return new HttpResult(200, "数据新增成功");
    }

    /**
     * 查询患者基础护理频率列表
     *
     * @param map
     * @return
     */
    public HttpResult findDataList(Map<String, Object> map) {
        errorIfEmpty(map, "查询参数不能为空");
        errorIfEmpty(map.get("patientId"), "查询患者id不能为空");
        List<BasicNursingSyncRecord> basicNursingSyncRecordList = basicNursingSyncRecordDao.queryList(map);
        return new HttpResult(200, basicNursingSyncRecordList, "查询患者数据成功");
    }

    /**
     * 根据基础护理频次同步数据到基础护理
     *
     * @return
     */
    public HttpResult syncDataInNursing(Map<String, Object> map) throws IllegalAccessException {
        errorIfEmpty(map, "同步参数不能为空");
        errorIfEmpty(map.get("patientId"), "同步患者id不能为空");
        List<BasicNursingSyncRecord> basicNursingSyncRecordList = basicNursingSyncRecordDao.queryList(map);
        if (CollectionUtils.isEmpty(basicNursingSyncRecordList))
            return new HttpResult(200, "同步数据不存在，同步失败");
        Date newDate = new Date();
        String dataStr = yyyyMMddSdfToString(newDate);
        Date endTime = strConversionDate(dataStr + " 23:59:59");
        if (Objects.nonNull(map.get("startTime")) && !Objects.equals(map.get("startTime"), ""))
            newDate = strConversionDate((String) map.get("startTime"));
        if (Objects.nonNull(map.get("endTime")) && !Objects.equals(map.get("endTime"), ""))
            endTime = strConversionDate((String) map.get("endTime"));
        for (BasicNursingSyncRecord basicNursingSyncRecord : basicNursingSyncRecordList) {
            if (Objects.isNull(basicNursingSyncRecord.getContent()))
                continue;
            // 如果不是是否需要赋值的则跳过
            if (isNeedSync(basicNursingSyncRecord))
                continue;
            // 如果频次为一天一次则单独做逻辑(只在当前点击时间新增一条)
            if (StringUtils.equals(basicNursingSyncRecord.getContent(), NURSING_SYNC_INTERVAL_QD))
                saveOrUpdateData(newDate, basicNursingSyncRecord);
            else
                saveNursing(newDate, endTime, basicNursingSyncRecord);
        }
        return new HttpResult(200, "基础护理数据自动同步成功");
    }

    /**
     * 新增或者修改基础护理数据
     */
    private void saveOrUpdateData(Date date, BasicNursingSyncRecord basicNursingSyncRecord) throws IllegalAccessException {
        PrimaryCare primaryCare = getDataByPatientIdAndCodeAndTime(date, basicNursingSyncRecord);
        if (Objects.isNull(primaryCare)) {
            insetData(basicNursingSyncRecord, date);
            // 如果新增患者为重症科室患者时，新增数据中心患者基础护理操作
            hisViewProduction.put(new HisViewDataDto(HIS_VIEW_EVENT_DC_HLCZJL_BZBWHL_HLCZ, primaryCare));
        } else {
            setContent(primaryCare, basicNursingSyncRecord.getCode());
            primaryCareDao.update(primaryCare);
            // 如果新增患者为重症科室患者时，新增数据中心患者基础护理操作
            hisViewProduction.put(new HisViewDataDto(HIS_VIEW_EVENT_DC_HLCZJL_BZBWHL_HLCZ, primaryCare));
        }
    }

    /**
     * 根据患者id,code,dateTime 查询基础护理数据
     *
     * @param date
     * @param basicNursingSyncRecord
     * @return
     */
    private PrimaryCare getDataByPatientIdAndCodeAndTime(Date date, BasicNursingSyncRecord basicNursingSyncRecord) {
        if (Objects.isNull(basicNursingSyncRecord))
            return null;
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("patientId", basicNursingSyncRecord.getPatientId());
        // 如果频次为一天一次则按当天日期查询是否有数据
        if (StringUtils.equals(basicNursingSyncRecord.getContent(), NURSING_SYNC_INTERVAL_QD))
            queryMap.put("dataDayTime", yyyyMMddSdfToString(date));
        else
            queryMap.put("dataTime", yyyyMMddHHmmSdfToString(date));
        return primaryCareDao.getDataByTimeAndPatientId(queryMap);
    }

    /**
     * 根据患者id查询最新的一条基础护理
     *
     * @param patientId
     * @return
     */
    private PrimaryCare findDataByPatientId(String patientId) {
        Map<String, Object> map = new HashMap<>();
        map.put("patientId", patientId);
        return primaryCareDao.getDataByTimeAndPatientId(map);
    }


    /**
     * 新增基础护理数据
     *
     * @param basicNursingSyncRecord
     * @param laterHoursDate
     * @return
     */
    private void insetData(BasicNursingSyncRecord basicNursingSyncRecord, Date laterHoursDate) throws IllegalAccessException {
        PrimaryCare primaryCare = new PrimaryCare();
        primaryCare.setId(getUUID());
        primaryCare.setPatientId(basicNursingSyncRecord.getPatientId());
        primaryCare.setStatus(1);
        primaryCare.setCreateTime(new Date());
        primaryCare.setDataTime(laterHoursDate);
        setContent(primaryCare, basicNursingSyncRecord.getCode());
        PrimaryCare oldPrimaryCare = findDataByPatientId(basicNursingSyncRecord.getPatientId());
        if (Objects.nonNull(oldPrimaryCare)) {
            if (StringUtils.isNotEmpty(oldPrimaryCare.getSignatureAgain()))
                primaryCare.setSignature(oldPrimaryCare.getSignatureAgain());
            else
                primaryCare.setSignature(oldPrimaryCare.getSignature());
        }
        primaryCareDao.insert(primaryCare);
    }

    /**
     * 根据code赋值对应字段值
     *
     * @param primaryCare
     * @param code
     * @throws IllegalAccessException
     */
    private void setContent(PrimaryCare primaryCare, String code) throws IllegalAccessException {
        Field[] fields = primaryCare.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldName = field.getName();
            if (StringUtils.equals(fieldName, code)) {
                field.set(primaryCare, "1");
                return;
            }
        }
    }

    /**
     * 根据频率新增护理数据
     *
     * @param basicNursingSyncRecord
     */
    private void saveNursing(Date date, Date endTime, BasicNursingSyncRecord basicNursingSyncRecord) {
        try {
            // 如果不是是否需要赋值的则跳过
            if (isNeedSync(basicNursingSyncRecord))
                return;
            // 获取频次间隔时长
            long intervalTime = getIntervalTime(basicNursingSyncRecord.getContent());
            if (intervalTime <= 0)
                return;
            // 获取n小时以后的时间
            Date laterHoursDate = date;
            do {
                // 对基础护理数据进行新增或者修改
                saveOrUpdateData(laterHoursDate, basicNursingSyncRecord);
                laterHoursDate = getLaterHoursDate(laterHoursDate, intervalTime);
            } while (laterHoursDate.getTime() <= endTime.getTime());
        } catch (Exception e) {
            logger.info("多次同步基础护理数据出错");
        }
    }

    /**
     * 判断是否需要自动同步
     *
     * @param basicNursingSyncRecord
     * @return
     */
    private boolean isNeedSync(BasicNursingSyncRecord basicNursingSyncRecord) {
        if (Objects.isNull(basicNursingSyncRecord)) {
            return true;
        }
        if (Objects.isNull(basicNursingSyncRecord.getCode())) {
            return true;
        }
        switch (basicNursingSyncRecord.getCode()) {
            case "blanketIceCap":
            case "lowerLimbsCure":
            case "rollOver":
            case "phlegmCharacter":
                return true;
            default:
                return false;
        }
    }

    /**
     * 查询是否存在旧的数据
     *
     * @param patientId
     * @param code
     * @return
     */
    private BasicNursingSyncRecord findOldData(String patientId, String code) {
        Map<String, Object> map = new HashMap<>();
        map.put("patientId", patientId);
        map.put("code", code);
        return basicNursingSyncRecordDao.getDataByPatientIdAndCode(map);
    }

    /**
     * 根据频率查询间隔时长
     *
     * @param value
     * @return
     */
    private long getIntervalTime(String value) {
        errorIfEmpty(value, "传输值不能为空");
        switch (value) {
            case NURSING_SYNC_INTERVAL_Q1:
                return 1;
            case NURSING_SYNC_INTERVAL_Q2:
                return 2;
            case NURSING_SYNC_INTERVAL_Q4:
                return 4;
            case NURSING_SYNC_INTERVAL_Q6:
                return 6;
            case NURSING_SYNC_INTERVAL_Q8:
                return 8;
            case NURSING_SYNC_INTERVAL_Q12:
                return 12;
            case NURSING_SYNC_INTERVAL_QD:
            case NURSING_SYNC_INTERVAL_NO:
            default:
                return 0;
        }
    }

    /**
     * 判断传值是否正确
     *
     * @param value
     * @return
     */
    private boolean estimateValue(String value) {
        errorIfEmpty(value, "传输值不能为空");
        switch (value) {
            case NURSING_SYNC_INTERVAL_Q1:
            case NURSING_SYNC_INTERVAL_Q2:
            case NURSING_SYNC_INTERVAL_Q4:
            case NURSING_SYNC_INTERVAL_Q6:
            case NURSING_SYNC_INTERVAL_Q8:
            case NURSING_SYNC_INTERVAL_Q12:
            case NURSING_SYNC_INTERVAL_QD:
            case NURSING_SYNC_INTERVAL_NO:
                return true;
            default:
                return false;
        }
    }
}
